package io.vertx.ext.mongo.impl.codec.json;
import io.vertx.core.json.JsonObject;
import org.bson.*;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.types.ObjectId;
import org.junit.Test;
import java.io.*;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.UUID;
import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
*
*/
public class JsonObjectCodecTest {
private JsonObject options = new JsonObject();
@Test
public void getBsonType_returnsDateTimeType_WhenValueIsJsonObjectAndContainsDateField() {
JsonObjectCodec codec = new JsonObjectCodec(options);
JsonObject value = new JsonObject();
value.put(JsonObjectCodec.DATE_FIELD, "2015-05-30T22:50:02+02:00");
assertEquals(BsonType.DATE_TIME, codec.getBsonType(value));
}
@Test
public void writeDocument_supportBsonDateTime() {
JsonObjectCodec codec = new JsonObjectCodec(options);
OffsetDateTime now = OffsetDateTime.now();
JsonObject dateValue = new JsonObject();
dateValue.put(JsonObjectCodec.DATE_FIELD, now.format(ISO_OFFSET_DATE_TIME));
JsonObject value = new JsonObject();
value.put("test", dateValue);
BsonDocument bsonResult = new BsonDocument();
BsonDocumentWriter writer = new BsonDocumentWriter(bsonResult);
codec.writeDocument(writer, "", value, EncoderContext.builder().build());
BsonValue resultValue = bsonResult.get("test");
assertEquals(BsonType.DATE_TIME, resultValue.getBsonType());
assertEquals(now.toInstant().toEpochMilli(), resultValue.asDateTime().getValue());
}
@Test
public void readDocument_supportBsonDateTime() {
JsonObjectCodec codec = new JsonObjectCodec(options);
Instant now = Instant.now();
BsonDocument bson = new BsonDocument();
bson.append("test", new BsonDateTime(now.toEpochMilli()));
BsonDocumentReader reader = new BsonDocumentReader(bson);
JsonObject result = codec.readDocument(reader, DecoderContext.builder().build());
JsonObject resultValue = result.getJsonObject("test");
assertEquals(now, OffsetDateTime.parse(resultValue.getString(JsonObjectCodec.DATE_FIELD)).toInstant());
}
@Test
public void writeDocument_supportBsonDateTimeWithMillis() {
JsonObjectCodec codec = new JsonObjectCodec(options);
JsonObject dateValue = new JsonObject();
dateValue.put(JsonObjectCodec.DATE_FIELD, "2011-12-03T10:15:30.500+01:00");
JsonObject value = new JsonObject();
value.put("test", dateValue);
BsonDocument bsonResult = new BsonDocument();
BsonDocumentWriter writer = new BsonDocumentWriter(bsonResult);
codec.writeDocument(writer, "", value, EncoderContext.builder().build());
long millis = 1322903730500L;
BsonValue resultValue = bsonResult.get("test");
assertEquals(BsonType.DATE_TIME, resultValue.getBsonType());
assertEquals(millis, resultValue.asDateTime().getValue());
String back =
OffsetDateTime.ofInstant(Instant.ofEpochMilli(1322903730500L), ZoneOffset.UTC).format(ISO_OFFSET_DATE_TIME);
// we encode always in UTC
assertEquals("2011-12-03T09:15:30.5Z", back);
}
@Test
public void writeDocument_supportBsonBinary() {
JsonObjectCodec codec = new JsonObjectCodec(options);
OffsetDateTime now = OffsetDateTime.now();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(now);
oos.close();
JsonObject binaryJson = new JsonObject();
binaryJson.put(JsonObjectCodec.BINARY_FIELD, baos.toByteArray());
JsonObject value = new JsonObject();
value.put("test", binaryJson);
BsonDocument bsonResult = new BsonDocument();
BsonDocumentWriter writer = new BsonDocumentWriter(bsonResult);
codec.writeDocument(writer, "", value, EncoderContext.builder().build());
BsonValue resultValue = bsonResult.get("test");
assertEquals(BsonType.BINARY, resultValue.getBsonType());
BsonBinary bsonBinary = resultValue.asBinary();
ByteArrayInputStream bais = new ByteArrayInputStream(bsonBinary.getData());
ObjectInputStream ois = new ObjectInputStream(bais);
OffsetDateTime reconstitutedNow = (OffsetDateTime) ois.readObject();
assertEquals(now, reconstitutedNow);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
assertTrue(false);
}
}
@Test
public void writeDocument_supportBsonBinaryUUID() {
JsonObjectCodec codec = new JsonObjectCodec(options);
UUID uuid = UUID.randomUUID();
byte[] byteUuid = ByteBuffer.allocate(16)
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits())
.array();
JsonObject value = new JsonObject();
value.put("test", new JsonObject()
.put(JsonObjectCodec.BINARY_FIELD, byteUuid)
.put(JsonObjectCodec.TYPE_FIELD, BsonBinarySubType.UUID_STANDARD.getValue())
);
BsonDocument bsonDocument = new BsonDocument();
BsonDocumentWriter writer = new BsonDocumentWriter(bsonDocument);
codec.writeDocument(writer, "", value, EncoderContext.builder().build());
BsonValue resultValue = bsonDocument.get("test");
assertEquals(BsonType.BINARY, resultValue.getBsonType());
BsonBinary bsonBinary = resultValue.asBinary();
ByteBuffer byteBuffer = ByteBuffer.wrap(bsonBinary.getData());
assertEquals(BsonBinarySubType.UUID_STANDARD.getValue(), bsonBinary.getType());
assertEquals(uuid, new UUID(byteBuffer.getLong(), byteBuffer.getLong()));
}
@Test
public void readDocument_supportBsonBinaryUUID() {
JsonObjectCodec codec = new JsonObjectCodec(options);
BsonDocument bsonDocument = new BsonDocument();
UUID uuid = UUID.randomUUID();
byte[] byteUuid = ByteBuffer.allocate(16)
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits())
.array();
bsonDocument.put("test", new BsonBinary(BsonBinarySubType.UUID_STANDARD, byteUuid));
BsonDocumentReader reader = new BsonDocumentReader(bsonDocument);
JsonObject result = codec.readDocument(reader, DecoderContext.builder().build());
JsonObject resultValue = result.getJsonObject("test");
assertTrue(resultValue.containsKey(JsonObjectCodec.BINARY_FIELD));
assertTrue(resultValue.containsKey(JsonObjectCodec.TYPE_FIELD));
ByteBuffer byteBuffer = ByteBuffer.wrap(resultValue.getBinary(JsonObjectCodec.BINARY_FIELD));
assertEquals(Integer.valueOf(BsonBinarySubType.UUID_STANDARD.getValue()), resultValue.getInteger(JsonObjectCodec.TYPE_FIELD));
assertEquals(uuid, new UUID(byteBuffer.getLong(), byteBuffer.getLong()));
}
@Test
public void readDocument_supportBsonBinary() {
JsonObjectCodec codec = new JsonObjectCodec(options);
Instant now = Instant.now();
BsonDocument bson = new BsonDocument();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(now);
oos.close();
bson.append("test", new BsonBinary(baos.toByteArray()));
BsonDocumentReader reader = new BsonDocumentReader(bson);
JsonObject result = codec.readDocument(reader, DecoderContext.builder().build());
JsonObject resultValue = result.getJsonObject("test");
byte[] bytes = resultValue.getBinary(JsonObjectCodec.BINARY_FIELD);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Instant reconstitutedNow = (Instant) ois.readObject();
assertEquals(now, reconstitutedNow);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
assertTrue(false);
}
}
@Test
public void readDocument_supportObjectId() {
JsonObjectCodec codec = new JsonObjectCodec(options);
BsonDocument bson = new BsonDocument();
ObjectId objectId = new ObjectId();
bson.append("test", new BsonObjectId(objectId));
BsonDocumentReader reader = new BsonDocumentReader(bson);
JsonObject result = codec.readDocument(reader, DecoderContext.builder().build());
String sObjectId = result.getJsonObject("test").getString("$oid");
assertEquals(objectId.toHexString(), sObjectId);
}
@Test
public void writeDocument_supportObjectId() {
JsonObjectCodec codec = new JsonObjectCodec(options);
ObjectId objectId = new ObjectId();
JsonObject oidJson = new JsonObject();
oidJson.put(JsonObjectCodec.OID_FIELD, objectId.toHexString());
JsonObject value = new JsonObject();
value.put("test", oidJson);
BsonDocument bsonResult = new BsonDocument();
BsonDocumentWriter writer = new BsonDocumentWriter(bsonResult);
codec.writeDocument(writer, "", value, EncoderContext.builder().build());
BsonValue resultValue = bsonResult.get("test");
assertEquals(BsonType.OBJECT_ID, resultValue.getBsonType());
BsonObjectId bsonObjectId = resultValue.asObjectId();
assertEquals(objectId.toHexString(), bsonObjectId.getValue().toHexString());
}
@Test
public void readDocument_supportBsonTimeStamp(){
JsonObjectCodec codec = new JsonObjectCodec(options);
int time = (int)(System.currentTimeMillis() / 1000L);
int increment = 5;
BsonDocument bson = new BsonDocument();
bson.append("test", new BsonTimestamp(time, increment));
BsonDocumentReader reader = new BsonDocumentReader(bson);
JsonObject result = codec.readDocument(reader, DecoderContext.builder().build());
JsonObject timeStampValue = result.getJsonObject("test").getJsonObject(JsonObjectCodec.TIMESTAMP_FIELD);
assertEquals(time, timeStampValue.getInteger(JsonObjectCodec.TIMESTAMP_TIME_FIELD).intValue());
assertEquals(increment, timeStampValue.getInteger(JsonObjectCodec.TIMESTAMP_INCREMENT_FIELD).intValue());
}
@Test
public void writeDocument_supportBsonTimeStamp(){
JsonObjectCodec codec = new JsonObjectCodec(options);
int time = (int)(System.currentTimeMillis() / 1000L);
int increment = 5;
JsonObject timeStampComponent = new JsonObject();
timeStampComponent.put(JsonObjectCodec.TIMESTAMP_TIME_FIELD, time);
timeStampComponent.put(JsonObjectCodec.TIMESTAMP_INCREMENT_FIELD, increment);
JsonObject timeStamp = new JsonObject();
timeStamp.put(JsonObjectCodec.TIMESTAMP_FIELD, timeStampComponent);
JsonObject value = new JsonObject();
value.put("test", timeStamp);
BsonDocument bsonResult = new BsonDocument();
BsonDocumentWriter writer = new BsonDocumentWriter(bsonResult);
codec.writeDocument(writer, "", value, EncoderContext.builder().build());
BsonValue resultValue = bsonResult.get("test");
assertEquals(BsonType.TIMESTAMP, resultValue.getBsonType());
assertEquals(time, resultValue.asTimestamp().getTime());
assertEquals(increment, resultValue.asTimestamp().getInc());
}
@Test
public void hexStringAsKeyDefault() {
JsonObject document = new JsonObject();
JsonObjectCodec codec = new JsonObjectCodec(options);
document = codec.generateIdIfAbsentFromDocument(document);
assertTrue(document.containsKey("_id"));
assertTrue(document.getValue("_id") instanceof String);
}
@Test
public void objectIdAsKeySpecified() {
JsonObject customOptions = new JsonObject().put("useObjectId", false);
JsonObject document = new JsonObject();
JsonObjectCodec codec = new JsonObjectCodec(customOptions);
document = codec.generateIdIfAbsentFromDocument(document);
assertTrue(document.containsKey("_id"));
assertTrue(document.getValue("_id") instanceof String);
}
@Test
public void objectIdAsKey() {
JsonObject customOptions = new JsonObject().put("useObjectId", true);
JsonObject document = new JsonObject();
JsonObjectCodec codec = new JsonObjectCodec(customOptions);
document = codec.generateIdIfAbsentFromDocument(document);
assertTrue(document.containsKey("_id"));
assertTrue(document.getValue("_id") instanceof JsonObject);
assertTrue(document.getJsonObject("_id").containsKey(JsonObjectCodec.OID_FIELD));
}
}